package todo_app

import (
	"fmt"
	"learning/gooop/saga/mqs/logger"
	"strings"
	"sync"
	"sync/atomic"
)

type tTodoReader struct {
	id      string
	rwmutex *sync.RWMutex
	items   []*TodoDTO
}

func newTodoReader() iTodoReader {
	it := new(tTodoReader)
	it.init()
	return it
}

func (me *tTodoReader) init() {
	id := fmt.Sprintf("tTodoReader.%d", atomic.AddInt32(&gReaderCounter, 1))
	me.id = id
	me.rwmutex = new(sync.RWMutex)

	GlobalEventBus.Sub(EventWriteTodoCmd, me.id, me.handleEvent)
	GlobalEventBus.Sub(EventLoadTodoCmd, me.id, me.handleEvent)
	GlobalEventBus.Sub(EventReadTodoCmd, me.id, me.handleEvent)
}

func (me *tTodoReader) handleEvent(e string, args interface{}) {
	switch e {
	case EventWriteTodoCmd:
		fallthrough
	case EventLoadTodoCmd:
		if v, ok := args.(*TodoEvent); ok {
			me.HandleTodoEvent(v)
		}
		break

	case EventReadTodoCmd:
		me.handleReadTodoList()
	}
}

func (me *tTodoReader) handleReadTodoList() {
	GlobalEventBus.Pub(EventReadTodoRet, me.All())
}

func (me *tTodoReader) All() []*TodoDTO {
	me.rwmutex.RLock()
	defer me.rwmutex.RUnlock()

	lst := make([]*TodoDTO, len(me.items))
	for i, it := range me.items {
		lst[i] = it
	}
	return lst
}

func (me *tTodoReader) HandleTodoEvent(e *TodoEvent) {
	me.rwmutex.Lock()
	defer me.rwmutex.Unlock()

	switch e.Tag {
	case OPCreated:
		me.items = append(me.items, e.Data.Clone())
		break

	case OPUpdated:
		for i, it := range me.items {
			if it.NO == e.Data.NO {
				me.items[i] = e.Data.Clone()
				break
			}
		}
		break

	case OPDeleted:
		for i, it := range me.items {
			if it.NO == e.Data.NO {
				lastI := len(me.items) - 1
				if i == lastI {
					me.items[i] = nil
				} else {
					me.items[i], me.items[lastI] = me.items[lastI], nil
				}

				me.items = me.items[:lastI]
				break
			}
		}
		break
	}

	lines := []string{}
	for _, it := range me.items {
		lines = append(lines, fmt.Sprintf("%v", it))
	}
	logger.Logf("tTodoReader.items: [%s]", strings.Join(lines, ", "))
}

var gReaderCounter int32 = 1
